Release 0.7.0 — MCP confirmations + wake_remote + install.sh#11
Closed
ThinkOffApp wants to merge 11 commits intomainfrom
Closed
Release 0.7.0 — MCP confirmations + wake_remote + install.sh#11ThinkOffApp wants to merge 11 commits intomainfrom
ThinkOffApp wants to merge 11 commits intomainfrom
Conversation
Adds a Model Context Protocol (MCP) server that exposes IAK's
tmux-backed wake / list / run primitives as MCP tools, so any
MCP-aware client (Claude Desktop / Code, Cursor, custom agents) can
drive the agent fleet directly without re-implementing the
nudge / send-keys protocol.
New files:
* src/mcp-server.mjs - MCP server (stdio transport).
4 tools: wake_ide, list_sessions, wake_all,
tmux_run. wake_all is config-aware: pulls
sessions from tmux.ide_session +
tmux.default_session + any per-adapter
session keys.
* bin/iak-mcp.mjs - CLI entry point (chmod +x, registered as
the `ide-agent-kit-mcp` bin in package.json
and as the `npm run mcp` script).
Dependencies:
* @modelcontextprotocol/sdk@^1.29.0
Verified by JSON-RPC handshake on stdio: initialize succeeds,
tools/list returns the 4 tools, tools/call name=list_sessions
returns the live tmux sessions on this host (6 found in smoke test).
One small implementation note worth flagging:
the tmux list-sessions format uses '|' as the field delimiter
rather than \t. Single-quoted shell strings do not interpret \t,
so tmux would receive literal backslash-t and emit it verbatim
instead of a tab, which broke the .split('\t') parser in early
iteration. '|' is safe for tmux session names (which are
alphanumeric + dash + underscore in IAK's conventions).
Wiring example in README. Drop in your MCP client config:
{
"mcpServers": {
"ide-agent-kit": {
"command": "node",
"args": ["/absolute/path/to/ide-agent-kit/bin/iak-mcp.mjs"]
}
}
}
…restart the client, the 4 tools appear in the picker, and you can
wake any IDE in the fleet from any agent that speaks MCP.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ession, tests, version-from-package Addresses every item in @claudemm's PR #10 review: * **Security (high) — tmux_run fail-closed.** When `tmux.allow` is missing or empty AND `mcp.allow_unrestricted` is not true, `tmux_run` is omitted from the tool list entirely (so it cannot be invoked at all). The boot log explains the decision: "[iak-mcp] tmux_run: enabled — tmux.allow has 5 pattern(s)" or "[iak-mcp] tmux_run: disabled — tmux.allow is missing or empty …". New helper decideTmuxRunMode() is exported and unit-tested. * **Fragile session discovery (medium) — explicit mcp.sessions.** Replaced the "scan every top-level config key for objects with a .session string" heuristic with an explicit `mcp.sessions: [...]` config key (preferred) plus the existing tmux.ide_session + tmux.default_session fallback. Unrelated keys (`sentry: {session: "warn"}`) no longer leak into wake_all targets. * **Hardcoded version (low).** Server now reads its own version from ../package.json at module load instead of hard-coding "0.6.1". Tracks future bumps automatically. * **Missing read_session tool (medium scope).** New tool wraps `tmux capture-pane -p -t <session> -S -<lines>` so MCP clients can see what an agent printed after a wake_ide. Lines clamped to [1, 2000]. * **No tests (medium).** Added test/mcp-server.test.mjs covering: - decideTmuxRunMode: missing config, empty allow, populated allow, allow_unrestricted with empty allow, allow_unrestricted=false. - configuredAgentSessions: empty config, explicit mcp.sessions, fallback to tmux.* keys, dedup, anti-fragility (does NOT scan unrelated keys), drops empty/non-string entries. - End-to-end stdio: server boots, advertises name + real semver version, exposes safe tools; with empty allowlist tmux_run is OMITTED; with mcp.allow_unrestricted=true tmux_run is INCLUDED. All 14 tests pass locally. * **Config pass-through.** loadConfig() now passes `mcp` through as `raw.mcp || {}` (same shape as `openclaw` already does), so MCP server-specific config keys round-trip without being dropped. README updated with the new tool table row, the new fail-closed behavior, and an explicit "MCP-specific config keys" subsection documenting `mcp.sessions` and `mcp.allow_unrestricted`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implements the Codewatch / GroupMind confirmation flow @Petrus asked for, on top of the MCP server already in this branch. Architecture: agent --MCP--> request_confirmation(prompt) | \ | \--> GroupMind room: posts the prompt with | /approve <id> · /deny <id> quick replies | (uses poller.api_key + mcp.confirmations.room) | \--> CLAWWATCH_GATE: posts the prompt to CodexMB's PR #8 receiver, which renders an Android interactive notification with Approve / Deny buttons that vibrate the watch. user taps Approve on watch (or types /approve <id> in chat) | v Codewatch's notification action POSTs to http://<callback_base>/intent/<id>/decision {decision: "approve"} | v iak-mcp's tiny HTTP server settles the intent, the in-memory promise resolves, request_confirmation returns synchronously. New files: * src/confirmations.mjs - in-memory intent registry (pending / decided) - createIntent + waitForDecision (synchronous-friendly) - decideIntent (idempotent for same decision; rejects flip-flops) - listIntents - startConfirmationsServer (POST /intent/:id/decision, GET /intents) with optional bearer auth (constant-time check) - announcers: makeGroupmindAnnouncer (HTTPS POST to groupmind.one/api/v1/messages), makeCodewatchAnnouncer (POST to the CLAWWATCH_GATE proxy) - composeAnnouncers (channel fan-out, per-channel error isolation) * test/confirmations.test.mjs — 15 tests: - createIntent: announces, returns id - decideIntent: validates, idempotent, rejects flip-flops - waitForDecision: immediate / blocking / timeout paths - listIntents: shows transitions - createIntent: tolerates announce failures - composeAnnouncers: fan-out + per-channel error isolation - HTTP: end-to-end POST settles a waiter; rejects bad json / unknown id; GET /intents lists; bearer auth gate works mcp-server.mjs additions: * Imports the confirmations module and conditionally starts the HTTP server + wires announcers based on mcp.confirmations config. * Registers four new tools — request_confirmation, list_intents, approve_intent, deny_intent — only if at least one channel is configured. Without a channel they're omitted (fail-closed, same pattern as tmux_run). * Boot log explains which channels are armed: "[iak-mcp] confirmations: enabled on http://127.0.0.1:8788 — channels: groupmind, codewatch" or "disabled — set mcp.confirmations.room (+ poller.api_key) and/or mcp.confirmations.codewatch_gate_url". README: * New "Confirmation flow" subsection with config keys + the four tools + an end-to-end walkthrough mapping the watch tap back to the MCP tool's return. Test suite: 76 / 76 pass (61 existing + 15 new). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…aemon * src/confirmations.mjs: GET / and /intents.html serve a small mobile-first HTML page with Approve / Deny tap targets per pending intent (inlined CSS/JS, no external assets, auto-refresh 2s). GroupMind announcer message body now includes a 'Tap to decide:' link to the same UI URL. * bin/iak-mcp-daemon.mjs (new): long-running daemon — starts the HTTP listener and a chat-reply poller that watches the configured GroupMind room every 5s for '/approve <id>' / '/deny <id>' and routes to the local intent endpoint. --demo flag posts a verification intent at boot. End-to-end verified live: tap the link in chat OR /approve <id> reply both land at /intent/<id>/decision and settle a waiting request_confirmation call. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
makeGroupmindAnnouncer now includes:
metadata: { actions: ["Approve","Deny"], intent_id,
intent_prompt, intent_session }
Companion change in antfarm (PR https://github.com/ThinkOffApp/antfarm/pull) renders inline Approve/Deny buttons on chat messages whose metadata carries both fields. Tap → posts `/approve <id>` as a chat reply → existing chat-reply poller in this daemon catches it and routes to /intent/:id/decision.
End-to-end: agent calls request_confirmation MCP tool → daemon posts to room with metadata → user taps Approve in GroupMind chat → chat reply posted → daemon catches reply → intent settled → MCP tool resolves with {decision: "approve"}.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the missing piece for unattended Claude Code:
- scripts/claudemb-poll.sh synced with the production version
on the MacBook (DM polling, focus-
preserving wake, cooldown, dual
/tmp file paths). Same script that
has been driving @claudemb's
auto-respond loop in the
thinkoff-development room.
- scripts/claudemb-wake.sh AppleScript injector. Activates
the Claude desktop app, types the
nudge ("check rooms"), then restores
focus to whatever app was frontmost.
- scripts/check-rooms-hook.sh UserPromptSubmit hook. Reads
/tmp/iak-new-messages.txt and
prepends to the prompt, then clears.
- docs/auto-wake.md Full setup + ASCII diagram +
env-var reference + troubleshooting.
Lets @claudemm and any other Claude desktop instance mirror the
auto-wake loop on a fresh box: drop the three scripts, wire the hook,
start the poller in tmux, done.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
scripts/claudecode-stop-resume.sh — Claude Code Stop hook that reads /tmp/iak-new-messages.txt and exits 2 with content on stderr, which makes Claude Code resume the turn with the new messages as additional context. No Accessibility permission needed. Pairs with the existing osascript wake path: the AppleScript wake covers from-idle (creates a new turn from nothing); the Stop hook covers in-flight (catches messages that arrive during an active turn). Use either or both depending on your macOS Accessibility state. Idea + reference impl from @claudemm on the Mac mini. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- src/confirmations.mjs: startConfirmationsServer now accepts an
optional `announce` callback. New POST /intent endpoint creates a
pending intent, wires up announcements via that callback, and
returns {ok, id}. Lets any HTTP caller (Bash gates, external
scripts, other agents) create confirmations without going through
stdio MCP.
- bin/iak-mcp-daemon.mjs: builds the announcer map up-front and
passes it into startConfirmationsServer so POST /intent fires
GroupMind/Codewatch announcements out of the box.
- src/mcp-server.mjs: request_confirmation now probes for a live
daemon at startup; when present, forwards intent creation +
decision polling via HTTP instead of starting an in-process
HTTP listener (which would conflict with the daemon's port).
Result: many MCP clients can share one daemon's intent registry.
- test/real-agent-demo.mjs: tiny MCP-SDK client harness that
spawns iak-mcp-server and calls request_confirmation, useful
for end-to-end testing.
Unblocks @claudemm's unification plan: a PreToolUse Bash gate on the
mini can now POST /intent + poll for the decision instead of going
through the older watch-gate.py /relay/events path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- src/confirmations.mjs: startConfirmationsServer accepts an optional
wakeScript path. New POST /wake endpoint runs the script with
the requested text (default "check rooms") and returns 202. Spawns
detached so the response returns immediately.
- bin/iak-mcp-daemon.mjs: defaults wakeScript to scripts/claudemb-wake.sh
in the repo. Override via mcp.confirmations.wake_script.
- src/mcp-server.mjs: new wake_remote MCP tool. Body {gateUrl, text}.
Forwards to the remote daemon's POST /wake. Lets any agent with the
IAK MCP registered nudge another agent's desktop app within ~500ms,
bypassing the 15s room-poll cadence.
Use case: claudemm posts a confirmation that needs claudemb's input.
Their daemon calls wake_remote(gateUrl="http://192.168.50.240:8788")
and claudemb's desktop Claude gets a "check rooms" prompt instantly
instead of waiting up to 15s for the next IAK poller tick.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
curl -fsSL https://raw.githubusercontent.com/ThinkOffApp/ide-agent-kit/main/scripts/install.sh | bash Idempotent. Verifies prereqs (node/git/tmux via brew), clones to ~/ide-agent-kit, npm installs, writes a starter config (with required-edit fields highlighted), wires UserPromptSubmit + Stop hooks into ~/.claude/settings.json, starts the daemon in a tmux session, prints the LAN URL the user pastes into CodeWatch. Does NOT generate keys, touch Accessibility (prints System Settings deep-link), or install Claude Code itself. Pairs with the in-app CodeWatch setup card (separate commit) so a user can go from "fresh phone + fresh Mac" to fully working in about 3 minutes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
See CHANGELOG.md for full notes. Major adds: request_confirmation + iak-mcp-daemon, POST /intent + POST /wake endpoints, wake_remote MCP tool for cross-machine nudge, GroupMind metadata.actions for inline Approve/Deny buttons (antfarm PR #13), Stop-hook auto-resume for the desktop app, one-shot macOS install.sh. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
To use Codex here, create an environment for this repo. |
Owner
Author
|
Superseded — feat/mcp-wake-ide already merged via PR #10 (commit c3cd47d) and v0.7.0 tagged + GitHub release published: https://github.com/ThinkOffApp/ide-agent-kit/releases/tag/v0.7.0. Same content. README + release notes updated post-merge. Thanks @claudemm. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Cuts a 0.7.0 release that bundles all the post-PR-#10 work from today's session into a single mergeable PR for petrus to land in the morning.
See
CHANGELOG.mdfor the complete rundown. Headline additions:request_confirmationMCP tool +iak-mcp-daemon(HTTP listener on 8788 + chat-reply poller).POST /intentandPOST /wakeHTTP endpoints on the daemon.wake_remoteMCP tool for cross-machine Claude-Code-to-Claude-Code nudge (verified end-to-end mini ↔ MacBook tonight).metadata.actions+metadata.intent_idon GroupMind announcements (paired with antfarm PR #13, already merged + deployed, which renders inline Approve/Deny buttons).scripts/claudecode-stop-resume.sh— Stop-hook auto-resume alternative to AppleScript wake (no Accessibility permission required).scripts/install.sh— one-shot macOS bootstrap.docs/auto-wake.mdsetup guide.mcp.sessionsarray.read_sessionMCP tool.Test plan
npm test— full suite green (76/76 verified by @claudemb and @CodexMB during PR feat: MCP server for waking and driving IDE / agent tmux sessions #10 round).wake_remotecross-machine: mini → MacBook landed osascript injection into desktop app, hook fired, response posted in room.scripts/install.shon a clean macOS (deferred — requires fresh Mac).Known limitations carried over
tmux_runallowlist still uses prefix matching; shell-chain bypass via&&/;unfixed (CodexMB review item, deferred to follow-up release).🤖 Generated with Claude Code